#pragma once
#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <pthread.h>
#include <unistd.h>
 
const int defalutnum = 5;
struct ThreadInfo
{
    pthread_t tid;
    std::string threadname;
};
template <class T>
class ThreadPool
{
public:
    void LOCK()
    {
        pthread_mutex_lock(&mutex_);
    }
    void UNLOCK()
    {
        pthread_mutex_unlock(&mutex_);
    }
    void WAKEUP()
    {
        pthread_cond_signal(&cond_);
    }
     void ThreadSleep()
    {
        pthread_cond_wait(&cond_, &mutex_);
    }
    bool IsQueueEmpty()
    {
        return tasks_.empty();
    }
public:
    //注意有个细节
     static void *HandlerTask(void *args)
     //这里如果不加static 那么就是类成员函数，其第一个参数是默认的隐藏参数（this指针）导致pthread_create()函数的第四个参数传参过来时不匹配
     //加了static则为静态成员函数，没有this指针
     {
         ThreadPool<T> *tp = static_cast<ThreadPool<T> *>(args);
        std::string name = tp->GetThreadName(pthread_self());
        while(true)
        {
            tp->LOCK();
            while(tp->IsQueueEmpty())
            {
                tp->ThreadSleep();
            }
            T t=tp->Pop();
            tp->UNLOCK();
            t();
            //std::cout << name << " run, "<< "result: " << t.GetResult() << std::endl;
        }
     }
     void Start()
     {
        int num=threads_.size();
        for(int i=0;i<num;i++)
        {
            threads_[i].threadname="thread-"+std::to_string(i+1);
            pthread_create(&threads_[i].tid,nullptr,HandlerTask,this);
        }
     }
     T Pop()
     {
        T t=tasks_.front();
        tasks_.pop();
        return t;
     }
     void Push(const T& in)
     {
        LOCK();
        tasks_.push(in);
        WAKEUP();
        UNLOCK();
     }
     //单例模式确保一个类只有一个实例，并提供一个全局访问点来获取这个实例，故设为静态成员函数（static）
     //因为：静态成员函数可以在没有类实例的情况下调用，并且它们只能访问静态成员。
     //懒汉方式实现单例模式(线程安全版本)-----双重检查锁模式
      static ThreadPool<T> *GetInstance()
    {
        if (nullptr == tp_) // 
        {
            pthread_mutex_lock(&lock_);
            if (nullptr == tp_)
            {
                std::cout << "log: singleton create done first!" << std::endl;
                tp_ = new ThreadPool<T>();
            }
            pthread_mutex_unlock(&lock_);
        }
        return tp_;
    }
//在多线程环境中，如果多个线程同时通过第一个检查, 都发现 tp_ 是 nullptr，那么这些线程中只有一个线程会在进入临界区前获取锁，其余线程需要等待。
//当第一个线程创建了实例，并离开了临界区（释放锁）时，余下的线程中只有一个将再次获取锁，然后重新检查 tp_ 是否为 null。在重新进入临界区后，此线程发现 tp_ 实例已经被创建，因此，其他线程不再创建新的实例。
//这种方法可以降低获取锁的频率，在实例已经创建后，大多数情况下，单个线程访问临界区即可。
    std::string GetThreadName(pthread_t tid)
    {
        for (const auto &ti : threads_)
        {
            if (ti.tid == tid)
                return ti.threadname;
        }
        return "None";
    }
private:
    ThreadPool(int num = defalutnum)
    : threads_(num)
    {
        pthread_mutex_init(&mutex_,nullptr);
        pthread_cond_init(&cond_,nullptr);
    }
     ~ThreadPool()
    {
        pthread_mutex_destroy(&mutex_);
        pthread_cond_destroy(&cond_);
    }
    //单例模式--只能实列化出一个对象
    //禁掉赋值和拷贝，将构造设为私有
    ThreadPool(const ThreadPool<T> &) = delete;
    const ThreadPool<T> &operator=(const ThreadPool<T> &) = delete; // a=b=c
private:
    std::vector<ThreadInfo> threads_;
    std::queue<T> tasks_;
    pthread_mutex_t mutex_;
    pthread_cond_t cond_;

    static ThreadPool<T> *tp_;
    static pthread_mutex_t lock_;
};
template<class T>
ThreadPool<T>* ThreadPool<T>::tp_=nullptr;
template<class T>
pthread_mutex_t ThreadPool<T>::lock_=PTHREAD_MUTEX_INITIALIZER;
